# -- coding: utf-8 --
from mip import Model, INTEGER, CONTINUOUS, BINARY, minimize, xsum, LinExpr
from enum import Enum


# 铁路线路
class RailwayLine:
    def __init__(self, list):  # list: ['北京', '天津', '济南', '南京', '上海']
        self.StationList = []
        self.SectionList = []
        self.PrevSection = {}
        self.NextSection = {}
        self.ODList = []
        for name in list:  # name: '北京'->'天津'->'济南'->'南京'->'上海'
            if len(self.StationList) == 0:  # 第一次len(self.StationList)是等于0的，后面都大于0
                self.StationList.append(name)  # 将name—>北京添加进StationList
            # 返回for name in list，此时name变成天津
            else:
                last = self.StationList[len(self.StationList) - 1]  # last:北京
                station = name  # name天津赋给station—name济南赋给station
                section = Section(last, station)
                self.StationList.append(station)  # StationList变为：北京、天津
                self.SectionList.append(section)
                self.PrevSection[station] = section
                self.NextSection[last] = section
        for index1 in range(len(self.StationList)):
            if self.StationList[index1]:
                sta1 = self.StationList[index1]
                for index2 in range(index1 + 1, len(self.StationList)):
                    if self.StationList[index2]:
                        self.ODList.append(Section(sta1, self.StationList[index2]))

    # 打印
    def Print(self):
        for station in self.StationList:
            if station == self.StationList[len(self.StationList) - 1]:
                print(station)
            else:
                print(station, '-->', end="")

    # 通过车站名称获取区间
    def GetSec(self, sta1, sta2):
        for sec in self.SectionList:
            if sec.start_station == sta1 and sec.end_station == sta2:
                return sec

    def GetOd(self, sta1, sta2):
        for od in self.ODList:
            if od.start_station == sta1 and od.end_station == sta2:
                return od

    # 获取除去首末站的其它车站
    def GetInterStation(self):
        for station in self.StationList:
            if not (station == self.StationList[0] or station == self.StationList[len(self.StationList) - 1]):
                yield station


# 区间
class Section:
    def __init__(self, station1, station2):
        self.start_station = station1
        self.end_station = station2
        self.Distance = 10


# 备选集
class AlternativeSet:
    def __init__(self):
        self.LineList = []


# 方案线
class TrainLine:
    def __init__(self, name):
        self.Name = name
        self.AlongStation = []
        self.AlongList = []
        self.AlongSection = []
        self.CoveredOD = []
        self.Mode = TranMode.Mode_Zl
        self.Capacity = 10

    # 增加停站
    def AddStop(self, station, isStop):
        self.AlongList.append(Stop(station, isStop))
        # 获取区间运行时间

    # 增加索引
    def BuildIndex(self, net):
        # 途径车站索引
        for index in self.AlongList:
            self.AlongStation.append(index.Station)
        # 途径区间索引
        for index in range(len(self.AlongList) - 1):
            self.AlongSection.append(net.GetSec(self.AlongList[index].Station, self.AlongList[index + 1].Station))
        # 覆盖OD索引
        for index1 in range(len(self.AlongList)):
            if self.AlongList[index1].Stop:
                sta1 = self.AlongList[index1].Station
                for index2 in range(index1 + 1, len(self.AlongList)):
                    if self.AlongList[index2].Stop:
                        self.CoveredOD.append(net.GetOd(sta1, self.AlongList[index2].Station))

    def Passed(self, section):
        return self.AlongSection.count(section)

    def Covered(self, section):
        for od in self.CoveredOD:
            if od.start_station == section.start_station and od.end_station == section.end_station:
                return True
        return False

    def Od_Section_Overlapped(self, od, section):
        od_start_index = self.AlongStation.index(od.start_station)
        od_end_index = self.AlongStation.index(od.end_station)
        section_start_index = self.AlongStation.index(section.start_station)
        section_end_index = self.AlongStation.index(section.end_station)
        return od_start_index <= section_start_index and od_end_index >= section_end_index


# 列车停站
class Stop:
    def __init__(self, station, stop):
        self.Station = station
        self.Stop = stop

    def IsPass(self):
        return self.Stop


# 各产品的运输需求
class CargoDemand:
    def __init__(self, od, M_type, num):
        self.od = od
        self.ProdType = M_type
        self.Num = num


# 运输模式枚举
class TranMode(Enum):
    Mode_Zl = 1  # 货运专列运输模式
    Mode_Qrc = 2  # 高铁确认车运输模式
    Mode_Yl = 3  # 客运动车组预留车厢运输模式
    Mode_Sd = 4  # 客运动车组捎带运输模式


# 产品种类枚举
class ProdType(Enum):
    Within_One_Day = 1  # 当日达
    Next_Morning = 2  # 次晨达
    Next_Day = 3  # 次日达
    After_Tomorrow = 4  # 隔日达


# 可以运输方式和产品的对应关系
class ModeTypeRelation:
    def __init__(self, tran_mode, product_type):
        self.Mode = tran_mode
        self.ProdType = product_type


class LineParameters:
    pass


# 生成小案例（改动）
def glb_generate_test_world():
    net = RailwayLine(['北京', '天津', '济南', '南京', '上海'])  # 线路上的停站

    # TODO: 输入OD距离
    net.GetOd('北京', '天津').Distance = 122
    net.GetOd('天津', '济南').Distance = 284
    net.GetOd('济南', '南京').Distance = 617
    net.GetOd('南京', '上海').Distance = 295

    # 下行
    alterSet = AlternativeSet()

    line1_Zl = TrainLine('Line1_zl')
    line1_Zl.AddStop('北京', True)
    line1_Zl.AddStop('天津', True)
    line1_Zl.AddStop('济南', True)
    line1_Zl.AddStop('南京', True)
    line1_Zl.AddStop('上海', True)
    line1_Zl.BuildIndex(net)
    line1_Zl.Mode = TranMode.Mode_Zl
    line1_Zl.Capacity = 120  # 每趟车的能力（吨）
    alterSet.LineList.append(line1_Zl)

    line1_Qrc = TrainLine('Line1_qrc')
    line1_Qrc.AddStop('北京', True)
    line1_Qrc.AddStop('天津', True)
    line1_Qrc.AddStop('济南', True)
    line1_Qrc.AddStop('南京', True)
    line1_Qrc.AddStop('上海', True)
    line1_Qrc.BuildIndex(net)
    line1_Qrc.Mode = TranMode.Mode_Qrc
    line1_Qrc.Capacity = 52.3  # 每趟车的能力（吨）
    alterSet.LineList.append(line1_Qrc)

    line1_Yl = TrainLine('Line1_yl')
    line1_Yl.AddStop('北京', True)
    line1_Yl.AddStop('天津', True)
    line1_Yl.AddStop('济南', True)
    line1_Yl.AddStop('南京', True)
    line1_Yl.AddStop('上海', True)
    line1_Yl.BuildIndex(net)
    line1_Yl.Mode = TranMode.Mode_Yl
    line1_Yl.Capacity = 8  # 每趟车的能力（吨）
    alterSet.LineList.append(line1_Yl)

    line1_Sd = TrainLine('line1_Sd')
    line1_Sd.AddStop('北京', True)
    line1_Sd.AddStop('天津', True)
    line1_Sd.AddStop('济南', True)
    line1_Sd.AddStop('南京', True)
    line1_Sd.AddStop('上海', True)
    line1_Sd.BuildIndex(net)
    line1_Sd.Mode = TranMode.Mode_Sd
    line1_Sd.Capacity = 5.21  # 每趟车的能力（吨）
    alterSet.LineList.append(line1_Sd)

    line2_Zl = TrainLine('Line2_zl')
    line2_Zl.AddStop('北京', True)
    line2_Zl.AddStop('天津', True)
    line2_Zl.BuildIndex(net)
    line2_Zl.Mode = TranMode.Mode_Zl
    line2_Zl.Capacity = 120  # 每趟车的能力（吨）
    alterSet.LineList.append(line2_Zl)

    line2_Qrc = TrainLine('Line2_qrc')
    line2_Qrc.AddStop('北京', True)
    line2_Qrc.AddStop('天津', True)
    line2_Qrc.BuildIndex(net)
    line2_Qrc.Mode = TranMode.Mode_Qrc
    line2_Qrc.Capacity = 52.3  # 每趟车的能力（吨）
    alterSet.LineList.append(line2_Qrc)

    line2_Yl = TrainLine('Line2_yl')
    line2_Yl.AddStop('北京', True)
    line2_Yl.AddStop('天津', True)
    line2_Yl.BuildIndex(net)
    line2_Yl.Mode = TranMode.Mode_Yl
    line2_Yl.Capacity = 8  # 每趟车的能力（吨）
    alterSet.LineList.append(line2_Yl)

    line2_Sd = TrainLine('Line2_sd')
    line2_Sd.AddStop('北京', True)
    line2_Sd.AddStop('天津', True)
    line2_Sd.BuildIndex(net)
    line2_Sd.Mode = TranMode.Mode_Sd
    line2_Sd.Capacity = 5.21  # 每趟车的能力（吨）
    alterSet.LineList.append(line2_Sd)

    line3_Zl = TrainLine('Line3_zl')
    line3_Zl.AddStop('北京', True)
    line3_Zl.AddStop('天津', False)
    line3_Zl.AddStop('济南', True)
    line3_Zl.BuildIndex(net)
    line3_Zl.Mode = TranMode.Mode_Zl
    line3_Zl.Capacity = 120  # 每趟车的能力（吨）
    alterSet.LineList.append(line3_Zl)

    line3_Qrc = TrainLine('Line3_qrc')
    line3_Qrc.AddStop('北京', True)
    line3_Qrc.AddStop('天津', False)
    line3_Qrc.AddStop('济南', True)
    line3_Qrc.BuildIndex(net)
    line3_Qrc.Mode = TranMode.Mode_Qrc
    line3_Qrc.Capacity = 52.3 # 每趟车的能力（吨）
    alterSet.LineList.append(line3_Qrc)

    line3_Yl = TrainLine('Line3_yl')
    line3_Yl.AddStop('北京', True)
    line3_Yl.AddStop('天津', False)
    line3_Yl.AddStop('济南', True)
    line3_Yl.BuildIndex(net)
    line3_Yl.Mode = TranMode.Mode_Yl
    line3_Yl.Capacity = 8  # 每趟车的能力（吨）
    alterSet.LineList.append(line3_Yl)

    line3_Sd = TrainLine('Line3_sd')
    line3_Sd.AddStop('北京', True)
    line3_Sd.AddStop('天津', False)
    line3_Sd.AddStop('济南', True)
    line3_Sd.BuildIndex(net)
    line3_Sd.Mode = TranMode.Mode_Sd
    line3_Sd.Capacity = 5.21  # 每趟车的能力（吨）
    alterSet.LineList.append(line3_Sd)

    line4_Zl = TrainLine('Line4_zl')
    line4_Zl.AddStop('北京', True)
    line4_Zl.AddStop('天津', False)
    line4_Zl.AddStop('济南', False)
    line4_Zl.AddStop('南京', True)
    line4_Zl.BuildIndex(net)
    line4_Zl.Mode = TranMode.Mode_Zl
    line4_Zl.Capacity = 120  # 每趟车的能力（吨）
    alterSet.LineList.append(line4_Zl)

    line4_Qrc = TrainLine('Line4_qrc')
    line4_Qrc.AddStop('北京', True)
    line4_Qrc.AddStop('天津', False)
    line4_Qrc.AddStop('济南', False)
    line4_Qrc.AddStop('南京', True)
    line4_Qrc.BuildIndex(net)
    line4_Qrc.Mode = TranMode.Mode_Qrc
    line4_Qrc.Capacity = 52.3  # 每趟车的能力（吨）
    alterSet.LineList.append(line4_Qrc)

    line4_Yl = TrainLine('Line4_yl')
    line4_Yl.AddStop('北京', True)
    line4_Yl.AddStop('天津', False)
    line4_Yl.AddStop('济南', False)
    line4_Yl.AddStop('南京', True)
    line4_Yl.BuildIndex(net)
    line4_Yl.Mode = TranMode.Mode_Yl
    line4_Yl.Capacity = 8  # 每趟车的能力（吨）
    alterSet.LineList.append(line4_Yl)

    line4_Sd = TrainLine('Line4_sd')
    line4_Sd.AddStop('北京', True)
    line4_Sd.AddStop('天津', False)
    line4_Sd.AddStop('济南', False)
    line4_Sd.AddStop('南京', True)
    line4_Sd.BuildIndex(net)
    line4_Sd.Mode = TranMode.Mode_Sd
    line4_Sd.Capacity = 5.21  # 每趟车的能力（吨）
    alterSet.LineList.append(line4_Sd)

    line5_Zl = TrainLine('Line5_zl')
    line5_Zl.AddStop('北京', True)
    line5_Zl.AddStop('天津', False)
    line5_Zl.AddStop('济南', False)
    line5_Zl.AddStop('南京', False)
    line5_Zl.AddStop('上海', True)
    line5_Zl.BuildIndex(net)
    line5_Zl.Mode = TranMode.Mode_Zl
    line5_Zl.Capacity = 120  # 每趟车的能力（吨）
    alterSet.LineList.append(line5_Zl)

    line5_Qrc = TrainLine('Line5_qrc')
    line5_Qrc.AddStop('北京', True)
    line5_Qrc.AddStop('天津', False)
    line5_Qrc.AddStop('济南', False)
    line5_Qrc.AddStop('南京', False)
    line5_Qrc.AddStop('上海', True)
    line5_Qrc.BuildIndex(net)
    line5_Qrc.Mode = TranMode.Mode_Qrc
    line5_Qrc.Capacity = 52.3 # 每趟车的能力（吨）
    alterSet.LineList.append(line5_Qrc)

    line5_Yl = TrainLine('Line5_yl')
    line5_Yl.AddStop('北京', True)
    line5_Yl.AddStop('天津', False)
    line5_Yl.AddStop('济南', False)
    line5_Yl.AddStop('南京', False)
    line5_Yl.AddStop('上海', True)
    line5_Yl.BuildIndex(net)
    line5_Yl.Mode = TranMode.Mode_Yl
    line5_Yl.Capacity = 8 # 每趟车的能力（吨）
    alterSet.LineList.append(line5_Yl)

    line5_Sd = TrainLine('Line5_sd')
    line5_Sd.AddStop('北京', True)
    line5_Sd.AddStop('天津', False)
    line5_Sd.AddStop('济南', False)
    line5_Sd.AddStop('南京', False)
    line5_Sd.AddStop('上海', True)
    line5_Sd.BuildIndex(net)
    line5_Sd.Mode = TranMode.Mode_Sd
    line5_Sd.Capacity = 5.21  # 每趟车的能力（吨）
    alterSet.LineList.append(line5_Sd)

    line6_Zl = TrainLine('Line6_zl')
    line6_Zl.AddStop('北京', True)
    line6_Zl.AddStop('天津', False)
    line6_Zl.AddStop('济南', False)
    line6_Zl.AddStop('南京', False)
    line6_Zl.AddStop('上海', True)
    line6_Zl.BuildIndex(net)
    line6_Zl.Mode = TranMode.Mode_Zl
    line6_Zl.Capacity = 120  # 每趟车的能力（吨）
    alterSet.LineList.append(line6_Zl)

    line6_Qrc = TrainLine('Line6_qrc')
    line6_Qrc.AddStop('北京', True)
    line6_Qrc.AddStop('天津', False)
    line6_Qrc.AddStop('济南', False)
    line6_Qrc.AddStop('南京', False)
    line6_Qrc.AddStop('上海', True)
    line6_Qrc.BuildIndex(net)
    line6_Qrc.Mode = TranMode.Mode_Qrc
    line6_Qrc.Capacity = 52.3  # 每趟车的能力（吨）
    alterSet.LineList.append(line6_Qrc)

    line6_Yl = TrainLine('Line6_yl')
    line6_Yl.AddStop('北京', True)
    line6_Yl.AddStop('天津', False)
    line6_Yl.AddStop('济南', False)
    line6_Yl.AddStop('南京', False)
    line6_Yl.AddStop('上海', True)
    line6_Yl.BuildIndex(net)
    line6_Yl.Mode = TranMode.Mode_Yl
    line6_Yl.Capacity = 8  # 每趟车的能力（吨）
    alterSet.LineList.append(line6_Yl)

    line6_Sd = TrainLine('Line6_sd')
    line6_Sd.AddStop('北京', True)
    line6_Sd.AddStop('天津', False)
    line6_Sd.AddStop('济南', False)
    line6_Sd.AddStop('南京', False)
    line6_Sd.AddStop('上海', True)
    line6_Sd.BuildIndex(net)
    line6_Sd.Mode = TranMode.Mode_Sd
    line6_Sd.Capacity = 5.21  # 每趟车的能力（吨）
    alterSet.LineList.append(line6_Sd)

    line7_Zl = TrainLine('Line7_zl')
    line7_Zl.AddStop('北京', True)
    line7_Zl.AddStop('天津', False)
    line7_Zl.AddStop('济南', False)
    line7_Zl.AddStop('南京', True)
    line7_Zl.AddStop('上海', True)
    line7_Zl.BuildIndex(net)
    line7_Zl.Mode = TranMode.Mode_Zl
    line7_Zl.Capacity = 120  # 每趟车的能力（吨）
    alterSet.LineList.append(line7_Zl)

    line7_Qrc = TrainLine('Line7_Qrc')
    line7_Qrc.AddStop('北京', True)
    line7_Qrc.AddStop('天津', False)
    line7_Qrc.AddStop('济南', False)
    line7_Qrc.AddStop('南京', True)
    line7_Qrc.AddStop('上海', True)
    line7_Qrc.BuildIndex(net)
    line7_Qrc.Mode = TranMode.Mode_Qrc
    line7_Qrc.Capacity = 52.3  # 每趟车的能力（吨）
    alterSet.LineList.append(line7_Qrc)

    line7_Yl = TrainLine('Line7_yl')
    line7_Yl.AddStop('北京', True)
    line7_Yl.AddStop('天津', False)
    line7_Yl.AddStop('济南', False)
    line7_Yl.AddStop('南京', True)
    line7_Yl.AddStop('上海', True)
    line7_Yl.BuildIndex(net)
    line7_Yl.Mode = TranMode.Mode_Yl
    line7_Yl.Capacity = 8  # 每趟车的能力（吨）
    alterSet.LineList.append(line7_Yl)

    line7_Sd = TrainLine('Line7_sd')
    line7_Sd.AddStop('北京', True)
    line7_Sd.AddStop('天津', False)
    line7_Sd.AddStop('济南', False)
    line7_Sd.AddStop('南京', True)
    line7_Sd.AddStop('上海', True)
    line7_Sd.BuildIndex(net)
    line7_Sd.Mode = TranMode.Mode_Sd
    line7_Sd.Capacity = 5.21  # 每趟车的能力（吨）
    alterSet.LineList.append(line7_Sd)


    line8_Zl = TrainLine('Line8_zl')
    line8_Zl.AddStop('北京', True)
    line8_Zl.AddStop('天津', False)
    line8_Zl.AddStop('济南', True)
    line8_Zl.AddStop('南京', False)
    line8_Zl.AddStop('上海', True)
    line8_Zl.BuildIndex(net)
    line8_Zl.Mode = TranMode.Mode_Zl
    line8_Zl.Capacity = 120  # 每趟车的能力（吨）
    alterSet.LineList.append(line8_Zl)

    line8_Qrc = TrainLine('Line8_qrc')
    line8_Qrc.AddStop('北京', True)
    line8_Qrc.AddStop('天津', False)
    line8_Qrc.AddStop('济南', True)
    line8_Qrc.AddStop('南京', False)
    line8_Qrc.AddStop('上海', True)
    line8_Qrc.BuildIndex(net)
    line8_Qrc.Mode = TranMode.Mode_Qrc
    line8_Qrc.Capacity = 52.3  # 每趟车的能力（吨）
    alterSet.LineList.append(line8_Qrc)

    line8_Yl = TrainLine('Line8_yl')
    line8_Yl.AddStop('北京', True)
    line8_Yl.AddStop('天津', False)
    line8_Yl.AddStop('济南', True)
    line8_Yl.AddStop('南京', False)
    line8_Yl.AddStop('上海', True)
    line8_Yl.BuildIndex(net)
    line8_Yl.Mode = TranMode.Mode_Yl
    line8_Yl.Capacity = 8  # 每趟车的能力（吨）
    alterSet.LineList.append(line8_Yl)

    line8_Sd = TrainLine('Line8_sd')
    line8_Sd.AddStop('北京', True)
    line8_Sd.AddStop('天津', False)
    line8_Sd.AddStop('济南', True)
    line8_Sd.AddStop('南京', False)
    line8_Sd.AddStop('上海', True)
    line8_Sd.BuildIndex(net)
    line8_Sd.Mode = TranMode.Mode_Sd
    line8_Sd.Capacity = 5.21  # 每趟车的能力（吨）
    alterSet.LineList.append(line8_Sd)

    line9_Zl = TrainLine('Line9_zl')
    line9_Zl.AddStop('北京', True)
    line9_Zl.AddStop('天津', False)
    line9_Zl.AddStop('济南', True)
    line9_Zl.AddStop('南京', True)
    line9_Zl.AddStop('上海', True)
    line9_Zl.BuildIndex(net)
    line9_Zl.Mode = TranMode.Mode_Zl
    line9_Zl.Capacity = 120  # 每趟车的能力（吨）
    alterSet.LineList.append(line9_Zl)

    line9_Qrc = TrainLine('Line9_qrc')
    line9_Qrc.AddStop('北京', True)
    line9_Qrc.AddStop('天津', False)
    line9_Qrc.AddStop('济南', True)
    line9_Qrc.AddStop('南京', True)
    line9_Qrc.AddStop('上海', True)
    line9_Qrc.BuildIndex(net)
    line9_Qrc.Mode = TranMode.Mode_Qrc
    line9_Qrc.Capacity = 52.3  # 每趟车的能力（吨）
    alterSet.LineList.append(line9_Qrc)

    line9_Yl = TrainLine('Line9_yl')
    line9_Yl.AddStop('北京', True)
    line9_Yl.AddStop('天津', False)
    line9_Yl.AddStop('济南', True)
    line9_Yl.AddStop('南京', True)
    line9_Yl.AddStop('上海', True)
    line9_Yl.BuildIndex(net)
    line9_Yl.Mode = TranMode.Mode_Yl
    line9_Yl.Capacity = 120  # 每趟车的能力（吨）
    alterSet.LineList.append(line9_Yl)

    line9_Sd = TrainLine('Line9_sd')
    line9_Sd.AddStop('北京', True)
    line9_Sd.AddStop('天津', False)
    line9_Sd.AddStop('济南', True)
    line9_Sd.AddStop('南京', True)
    line9_Sd.AddStop('上海', True)
    line9_Sd.BuildIndex(net)
    line9_Sd.Mode = TranMode.Mode_Sd
    line9_Sd.Capacity = 5.21  # 每趟车的能力（吨）
    alterSet.LineList.append(line9_Sd)

    params = LineParameters()
    params.Fixed_Cost = {
        TranMode.Mode_Zl: 23156.21,
        TranMode.Mode_Qrc: 6015.49,
        TranMode.Mode_Sd: 761.94,
        TranMode.Mode_Yl: 721.39
    }  # 固定成本
    params.Flex_Cost = {
        TranMode.Mode_Zl: 0.0023,
        TranMode.Mode_Qrc: 0,
        TranMode.Mode_Sd: 0.0018,
        TranMode.Mode_Yl: 0
    }  # 可变成本
    params.Capacity = {
        net.GetSec('北京', '天津'): 10,  # 区间能力约束（列）
        net.GetSec('天津', '济南'): 10,
        net.GetSec('济南', '南京'): 10,
        net.GetSec('南京', '上海'): 10, }

    params.CargoDemand = [
        CargoDemand(net.GetOd('北京', '天津'), ProdType.Within_One_Day, 6.618),
        CargoDemand(net.GetOd('北京', '天津'), ProdType.Next_Morning, 28.293),
        CargoDemand(net.GetOd('北京', '天津'), ProdType.Next_Day, 24.24),
        CargoDemand(net.GetOd('北京', '天津'), ProdType.After_Tomorrow, 14.548),
        CargoDemand(net.GetOd('北京', '济南'), ProdType.Within_One_Day, 13.739),
        CargoDemand(net.GetOd('北京', '济南'), ProdType.Next_Morning, 58.737),
        CargoDemand(net.GetOd('北京', '济南'), ProdType.Next_Day, 50.322),
        CargoDemand(net.GetOd('北京', '济南'), ProdType.After_Tomorrow, 30.202),
        CargoDemand(net.GetOd('北京', '南京'), ProdType.Within_One_Day, 4.849),
        CargoDemand(net.GetOd('北京', '南京'), ProdType.Next_Morning, 20.731),
        CargoDemand(net.GetOd('北京', '南京'), ProdType.Next_Day, 17.761),
        CargoDemand(net.GetOd('北京', '南京'), ProdType.After_Tomorrow, 10.66),
        CargoDemand(net.GetOd('北京', '上海'), ProdType.Within_One_Day, 14.368),
        CargoDemand(net.GetOd('北京', '上海'), ProdType.Next_Morning, 61.424),
        CargoDemand(net.GetOd('北京', '上海'), ProdType.Next_Day, 252.624),
        CargoDemand(net.GetOd('北京', '上海'), ProdType.After_Tomorrow, 31.584),
        CargoDemand(net.GetOd('天津', '济南'), ProdType.Within_One_Day, 1.886),
        CargoDemand(net.GetOd('天津', '济南'), ProdType.Next_Morning, 8.062),
        CargoDemand(net.GetOd('天津', '济南'), ProdType.Next_Day, 6.907),
        CargoDemand(net.GetOd('天津', '济南'), ProdType.After_Tomorrow, 4.145),
        CargoDemand(net.GetOd('天津', '南京'), ProdType.Within_One_Day, 0.754),
        CargoDemand(net.GetOd('天津', '南京'), ProdType.Next_Morning, 3.225),
        CargoDemand(net.GetOd('天津', '南京'), ProdType.Next_Day, 2.763),
        CargoDemand(net.GetOd('天津', '南京'), ProdType.After_Tomorrow, 1.658),
        CargoDemand(net.GetOd('天津', '上海'), ProdType.Within_One_Day, 1.616),
        CargoDemand(net.GetOd('天津', '上海'), ProdType.Next_Morning, 6.91),
        CargoDemand(net.GetOd('天津', '上海'), ProdType.Next_Day, 5.92),
        CargoDemand(net.GetOd('天津', '上海'), ProdType.After_Tomorrow, 3.553),
        CargoDemand(net.GetOd('济南', '南京'), ProdType.Within_One_Day, 1.85),
        CargoDemand(net.GetOd('济南', '南京'), ProdType.Next_Morning, 7.908),
        CargoDemand(net.GetOd('济南', '南京'), ProdType.Next_Day, 6.775),
        CargoDemand(net.GetOd('济南', '南京'), ProdType.After_Tomorrow, 4.066),
        CargoDemand(net.GetOd('济南', '上海'), ProdType.Within_One_Day, 3.466),
        CargoDemand(net.GetOd('济南', '上海'), ProdType.Next_Morning, 14.818),
        CargoDemand(net.GetOd('济南', '上海'), ProdType.Next_Day, 12.696),
        CargoDemand(net.GetOd('济南', '上海'), ProdType.After_Tomorrow, 7.62),
        CargoDemand(net.GetOd('南京', '上海'), ProdType.Within_One_Day, 4.957),
        CargoDemand(net.GetOd('南京', '上海'), ProdType.Next_Morning, 21.191),
        CargoDemand(net.GetOd('南京', '上海'), ProdType.Next_Day, 18.155),
        CargoDemand(net.GetOd('南京', '上海'), ProdType.After_Tomorrow, 10.896),
    ]

    params.Forbidden_Relations = [
        ModeTypeRelation(TranMode.Mode_Qrc, ProdType.Within_One_Day),  # 确认车不能运当日达
    ]  # 不受支持的模式-产品关系

    return net, alterSet, params


# 求解问题
def glb_solve_mip(net, alterSet, params):
    '''
    M分别表示四种高铁快递运输模式
        m=1表示货运专列运输模式， m=2表示高铁确认车运输模式， m=3表示客运动车组预留车厢运输模式，
        m=4表示客运动车组捎带运输模式
    N分别表示四种高铁快递产品
        n=1表示当日达， n=2表示次晨达， n=3表示次日达, n=4表示隔日达）
    '''


    model = Model()
    frequency_var = {}
    p_var = {}

    # 初始化变量
    for line in alterSet.LineList:
        frequency_var[line] = model.add_var(lb=0, ub=999, var_type=INTEGER, name=line.Name)
        p_var[line] = {(m, od): model.add_var(var_type=CONTINUOUS) for m in ProdType for od in
                   line.CoveredOD}  # 变量q - 每条方案线运送 不同OD, 不同类型服务 的数量

    # 约束1 ：需求满足约束
    for d in params.CargoDemand:
        # 不是每个line都覆盖每个OD
        result = LinExpr()
        for line in alterSet.LineList:
            if line.Covered(d.od):
                result = result + p_var[line][d.ProdType, d.od]
        model += result >= d.Num

    # 约束2：区间能力约束
    for sec in net.SectionList:  # 遍历所有的区间
        model += xsum(line.Passed(sec) * frequency_var[line] for line in alterSet.LineList) <= params.Capacity[
            sec]

    # 约束3：列车装载能力约束
    for line in alterSet.LineList:
        for sec in line.AlongSection:
            model += xsum(p_var[line][m, od] * line.Od_Section_Overlapped(od, sec) for m in ProdType for od in
                          line.CoveredOD) <= frequency_var[line] * line.Capacity

    # 约束4：产品供给特征约束
    for relation in params.Forbidden_Relations:
        for line in alterSet.LineList:
            if line.Mode == relation.Mode:
                for od in line.CoveredOD:
                    model += p_var[line][relation.ProdType, od] == 0


    # 目标：成本最小
    model.objective = minimize(xsum(params.Fixed_Cost[line.Mode] * frequency_var[line] for line in alterSet.LineList) +
                               xsum(params.Flex_Cost[line.Mode] * od.Distance * p_var[line][m, od] for line in
                                    alterSet.LineList for m in ProdType for od in line.CoveredOD))

    # 求解
    model.write("model.lp")
    model.max_mip_gap = 0.01
    model.verbose = 0
    model.optimize()

    # 输出
    if model.num_solutions:
        for line in alterSet.LineList:
            if frequency_var[line].x > 0:
                print('方案线:{0},运输模式{1},开行频率:{2}'.format(line.Name, line.Mode, frequency_var[line].x))
                for od in line.CoveredOD:
                    for m in ProdType:
                        if p_var[line][m, od].x > 0:
                            print('\t{0}->{1},产品类型{2},运量：{3}'.format(od.start_station, od.end_station, m, p_var[line][m, od].x))
        print('目标函数值:', format(model.objective_value))


# Press the green button in the gutter to run the script.
if __name__ == '__main__':
    net, alterSet, params = glb_generate_test_world()  # 线路上的停站
    net.Print()

    # data = pd.read_csv('运输量.csv', header=0, encoding='gbk')
    # d = data.values.tolist()
    # for row in d:
    #     demand = CargoDemand(net.GetSec(row[0], row[1]), row[2], row[3])

glb_solve_mip(net, alterSet, params)
